package com.qingfeng.activiti.service.impl;

import com.qingfeng.activiti.mapper.AssignmentMapper;
import com.qingfeng.activiti.modeler.NewProcessInstance;
import com.qingfeng.activiti.service.IBusinessStatusService;
import com.qingfeng.activiti.service.IProcessInstanceService;
import com.qingfeng.activiti.service.impl.image.CustomProcessDiagramGenerator;
import com.qingfeng.entity.activiti.BusinessStatus;
import com.qingfeng.entity.activiti.BusinessStatusEnum;
import com.qingfeng.entity.activiti.Result;
import com.qingfeng.entity.activiti.StartREQ;
import com.qingfeng.utils.PageData;
import com.qingfeng.utils.Verify;
import org.activiti.bpmn.model.*;
import org.activiti.bpmn.model.Process;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.history.*;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.persistence.entity.ExecutionEntityImpl;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.thymeleaf.util.DateUtils;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author cb
 * @Description TODO
 * @date 2023/6/9
 */

@Service
public class ProcessInstanceService extends ActivitiService  implements IProcessInstanceService {


    @Autowired
    IBusinessStatusService businessStatusService;

    @Autowired
    AssignmentMapper assignmentMapper;



    @Override
    public Result startProcess(StartREQ req) {

        // 2. 表单组件名设置到流程变量中，后面查询历史审批记录需要
        Map<String, Object> variables = req.getVariables(); // 前端已经传递了当前申请信息｛entity: {业务申请数据}}
       // variables.put("formName", processConfig.getFormName());

        // 判断办理人为空，则直接结束
        List<String> assignees = req.getAssignees();
        if(CollectionUtils.isEmpty(assignees)) {
            return Result.error("请指定审批人");
        }

        // 3. 启动流程实例（提交申请）
        Authentication.setAuthenticatedUserId("chenbo");
        ProcessInstance pi =
                runtimeService.startProcessInstanceByKey(req.getBusinessKey(),
                        req.getBusinessKey(), variables);

        // 将流程定义名称 作为 流程实例名称
        runtimeService.setProcessInstanceName(pi.getProcessInstanceId(), pi.getProcessDefinitionName());

        // 4. 设置任务办理人
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(pi.getId()).list();
        for (Task task : taskList) {
            if(assignees.size() == 1) {
                // 如果只能一个办理人，则直接设置为办理人
                taskService.setAssignee(task.getId(), assignees.get(0));
            }else {
                // 多个办理人，则设置为候选人
                for(String assignee: assignees) {
                    taskService.addCandidateUser(task.getId(), assignee);
                }
            }
        }

        // 5. 更新业务状态为：办理中, 和流程实例id
         businessStatusService.updateState(req.getBusinessKey(),
                BusinessStatusEnum.PROCESS,
                pi.getProcessInstanceId());
             return Result.ok();
    }

    @Override
    public Result cancel(String businessKey, String procInstId, String message) {
        // 1. 删除当前流程实例
        runtimeService.deleteProcessInstance(procInstId,
                message+ " 主动撤回了当前申请：" + message);

        // 2. 删除历史记录
        historyService.deleteHistoricProcessInstance(procInstId);
        historyService.deleteHistoricTaskInstance(procInstId);

        // 3. 更新业务状态
         businessStatusService.updateState(businessKey, BusinessStatusEnum.CANCEL, "");

         return  Result.ok();
    }

    @Override
    public Result getFormNameByProcInstId(String procInstId) {
        // 通过流程实例id获取流程实例相关数据：流程变量
        HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery()
                .includeProcessVariables()
                .processInstanceId(procInstId).singleResult();

        return Result.ok(hpi.getProcessVariables().get("formName"));
    }

    @Override
    public Result getHistoryInfoList(String procInstId) {
        // 查询每任务节点历史办理情况
        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(procInstId)
                .orderByHistoricTaskInstanceStartTime()
                .asc()
                .list();

        List<Map<String, Object>> records = new ArrayList<>();
        for (HistoricTaskInstance hti : list) {
            Map<String, Object> result = new HashMap<>();
            result.put("taskId", hti.getId()); // 任务ID
            result.put("taskName", hti.getName()); // 任务名称
            result.put("processInstanceId", hti.getProcessInstanceId()); //流程实例ID
            //result.put("startTime", DateUtils.format(hti.getStartTime())); // 开始时间
           // result.put("endTime", DateUtils.format(hti.getEndTime())); // 结束时间
            result.put("status", hti.getEndTime() == null ? "待处理": "已处理"); // 状态
            result.put("assignee", hti.getAssignee()); // 办理人

            // 撤回原因
            String message = hti.getDeleteReason();
            if(StringUtils.isEmpty(message)) {
                List<Comment> taskComments = taskService.getTaskComments(hti.getId());
                message = taskComments.stream()
                        .map(m -> m.getFullMessage()).collect(Collectors.joining("。"));
            }
            result.put("message", message);

            records.add(result);
        }

        return Result.ok(records);
    }

    @Override
    public void getHistoryProcessImage(String prodInstId, HttpServletResponse response) {

    }


    @Override
    public Result deleteProcInstAndHistory(String procInstId) {
        // 1. 查询历史流程实例
        HistoricProcessInstance instance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(procInstId).singleResult();

        // 2. 删除历史流程实例
        historyService.deleteHistoricProcessInstance(procInstId);
        historyService.deleteHistoricTaskInstance(procInstId);

        // 3. 更新流程业务状态, 注意：流程实例id传递一个空字符串""，不要是null,不然无法更新到
         businessStatusService.updateState(instance.getBusinessKey(), BusinessStatusEnum.DELETE, "");
         return Result.ok();
    }



    public void proNode(Task pretask) {

//        String nodeId="UserTask_0mkm9h7";

        String nodeId = pretask.getId();

        String processInstanceId=pretask.getProcessInstanceId();

        //网关集合

        List<Gateway> gateways = new ArrayList<>();

        //用户任务集合

        List<UserTask> userTasks = new ArrayList<>();

        //网关节点id

        List<String> gatewayNodelIdList = new ArrayList<>();

        //用户任务节点id

        List<String> usertaskNodelIdList = new ArrayList<>();

        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();

        String processDefinitionId = processInstance.getProcessDefinitionId();

        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();

        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());

        List<Process> processes = bpmnModel.getProcesses();

        Process process = processes.get(0);

        Collection<FlowElement> flowElements = process.getFlowElements();

        flowElements.forEach(flowElement -> {

            if (flowElement instanceof Gateway) {

                gatewayNodelIdList.add(flowElement.getId());

                gateways.add((Gateway) flowElement);

            }

            if (flowElement instanceof UserTask) {

                usertaskNodelIdList.add(flowElement.getId());

                userTasks.add((UserTask) flowElement);

            }

        });

        //存放上一节点的nodeId（可能存在多个）

        List<String> frontNodeIdlist = new ArrayList<>();

        for (UserTask userTask : userTasks) {

            //获取当前节点的入线

            List<SequenceFlow> incomingFlows = userTask.getIncomingFlows();

            for (SequenceFlow incomingFlow : incomingFlows) {

                String sourceRef = incomingFlow.getSourceRef();

                String targetRef = incomingFlow.getTargetRef();

                //固定入线的目标源（targetRef），判断入线的源头（sourceRef）

                if (nodeId.equals(targetRef)) {

                    //如果当前任务的上一节点是网关，继续判断网关节点的入线

                    if (gatewayNodelIdList.contains(sourceRef)) {

                        for (Gateway gateway : gateways) {

                            List<SequenceFlow> incomingFlowsGateWay = gateway.getIncomingFlows();

                            for (SequenceFlow sequenceFlow : incomingFlowsGateWay) {

                                String sourceRefGateWay = sequenceFlow.getSourceRef();

                                String targetRefGateWay = sequenceFlow.getTargetRef();

                                // 将targetRef变为网关节点的nodeId,继续向上搜索

                                if (sourceRef.equals(targetRefGateWay)) {

                                    frontNodeIdlist.add(sourceRefGateWay);

                                }

                            }

                        }

                    } else {

                        //上一节点不是网关，直接放入

                        frontNodeIdlist.add(sourceRef);

                    }

                }

            }

        }

        frontNodeIdlist.forEach(System.out::println);

    }


    //判定是否第一个用户任务


    public Boolean IsFirstUerTask(Task task,String userid){

        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(task.getTaskDefinitionKey());
        UserTask userTask = (UserTask) flowNode;
        List<SequenceFlow> incomingFlows = userTask.getIncomingFlows();
        SequenceFlow sequenceFlow = incomingFlows.get(0);
        FlowElement sourceFlowElement = sequenceFlow.getSourceFlowElement();


        if (sourceFlowElement instanceof StartEvent){
            return  true;

        }
        if(sourceFlowElement  instanceof  UserTask){
            UserTask userTask1 = (UserTask) sourceFlowElement;

            List<SequenceFlow> incomingFlows1 = userTask1.getIncomingFlows();
            SequenceFlow sequenceFlow1 = incomingFlows1.get(0);
            FlowElement sourceFlowElement1 = sequenceFlow1.getSourceFlowElement();
            if (sourceFlowElement1 instanceof StartEvent){
                return  true;
            }
        }

            return   false;
    }

    /**
     * 根据sql获取流程实例列表数据
     * @param pd 参数
     * @return list
     */
    public List<NewProcessInstance> getProcessInstanceList(PageData pd){
        String page = Verify.verifyIsNotNull(pd.get("page"))?pd.get("page").toString():"1"; //当前页
        String pageSize = Verify.verifyIsNotNull(pd.get("limit"))?pd.get("limit").toString():"10"; //页面大小
        String processInstanceId = Verify.verifyIsNotNull(pd.get("processInstanceId"))?pd.get("processInstanceId").toString():"";//流程实例id
        String processDefinitionName = Verify.verifyIsNotNull(pd.get("processDefinitionName"))?pd.get("processDefinitionName").toString()
                :"";//流程定义name
        String processDefinitionId = Verify.verifyIsNotNull(pd.get("processDefinitionId"))?pd.get("processDefinitionId").toString():"";//流程定义ID
        String processDefinitionKey = Verify.verifyIsNotNull(pd.get("processDefinitionKey"))?pd.get("processDefinitionKey").toString():"";//流程定义Key
        Integer offest = (Integer.parseInt(page)-1) * Integer.parseInt(pageSize);
        return assignmentMapper.getProcessInstanceList(offest,processInstanceId,processDefinitionName,processDefinitionId,
                processDefinitionKey);
    }

}
